﻿package components {
	
	import com.greensock.TweenLite;
	import com.limetalks.data.Stream;
	import com.limetalks.events.StreamSelected;
	
	import flash.display.Graphics;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	
	import mx.controls.Alert;
	
	public class Sphere extends MovieClip {
		
		//private var boll:Sprite; // наши оси у сферы
		private var bodyBoll:Sprite; // объект который будет содержать оси и который мы будем крутить
		private var body:Sprite; // заливка для того что бы можно было вешать события миши на обект не прицеливаясь
		
		public var mcList:Array;
		private var d:Number = 300; 
		private var lasta:Number;
		private var lastb:Number;
		private var sa:Number;
		private var ca:Number;
		private var sb:Number;
		private var cb:Number;
		private var sc:Number;
		private var cc:Number;

		private var tspeed:Number = 1;
		private var radius:Number = 150;
		private var dtr:Number = Math.PI/180;
		private var elementCount:Number;
		
		private var _root:MovieClip;
		
		public var rotateMode:Boolean = true;
		
		public function Sphere(data:Array, parentMC:MovieClip, radiusP:Number=140) {
			
			super();
			_root = parentMC;
			this.radius = radiusP;			
			mcList = [];			
			createStreams(data);
			this.bodyBoll = new Sprite();
			this.body = new Sprite();
			addEventListener(Event.ENTER_FRAME, updateTags);
		}
	
		private function depthSort():void {
			
			mcList.sortOn("cz", Array.DESCENDING | Array.NUMERIC);
			for(var i:Number=0; i<mcList.length; i++ )
				this.setChildIndex(mcList[i],i);
		}
		
		private function updateTags(e:Event):void {
			
			if(rotateMode) {
				
				var a:Number;
				var b:Number;
				//if(active) {
					a = (-Math.min( Math.max(mouseY, -d ), d ) / radius ) * tspeed;
					b = (Math.min( Math.max(mouseX, -d ), d ) /radius ) * tspeed;
				//} else {
					//a = lasta * 0.89;
					//b = lastb * 0.89;
				//}
				lasta = a;
				lastb = b;
				// if a and b under threshold, skip motion calculations to free up the processor
				if( Math.abs(a) > 0.01 || Math.abs(b) > 0.01 ){
					var c:Number = 0;
					sineCosine(a,b,c);
					// bewegen van de punten
					for(var j:Number=0; j<mcList.length; j++) {
						//if(!mcList[j].isDragged) {
							// multiply positions by a x-rotation matrix
							var rx1:Number = mcList[j].cx;
							var ry1:Number = mcList[j].cy * ca + mcList[j].cz * -sa;
							var rz1:Number = mcList[j].cy * sa + mcList[j].cz * ca;
							// multiply new positions by a y-rotation matrix
							var rx2:Number = rx1 * cb + rz1 * sb;
							var ry2:Number = ry1;
							var rz2:Number = rx1 * -sb + rz1 * cb;
							// multiply new positions by a z-rotation matrix
							var rx3:Number = rx2 * cc + ry2 * -sc;
							var ry3:Number = rx2 * sc + ry2 * cc;
							var rz3:Number = rz2;
							// set arrays to new positions
							mcList[j].cx = rx3;
							mcList[j].cy = ry3;
							mcList[j].cz = rz3;
							// add perspective
							mcList[j].per = d / (d+rz3);
							// setmc position, scale, alpha
							if(!mcList[j].isDragged) {
								mcList[j].x = rx3 * mcList[j].per;
								mcList[j].y = ry3 * mcList[j].per;
								//this.setChildIndex(mcList[j],mcList[j].cz);
								//mcList[j].swapDepths(mcList[0]);
								//mcList[j].z = rz3;
								///mcList[j].alert
								mcList[j].scaleX = mcList[j].scaleY = mcList[j].per*2/3;
								//mcList[j].alpha = mcList[j].per*3/4;
							}
						//}
					}
					depthSort();
				}
			}
			//rotateMode = false;
			//var are:MovieClip = new MovieClip();
			//are.
		}
		
		private function sineCosine(a:Number, b:Number, c:Number):void {
			sa = Math.sin(a * dtr);
			ca = Math.cos(a * dtr);
			sb = Math.sin(b * dtr);
			cb = Math.cos(b * dtr);
			sc = Math.sin(c * dtr);
			cc = Math.cos(c * dtr);
		}
		
		private function createStreams(data:Array):void {
			
			mcList = new Array();
			for each (var s:Stream in data)
				mcList.push(new StreamMC(this, s));
			
			elementCount = mcList.length;
			
			var phi:Number = 0;
			var theta:Number = 0;
			
			var i:int;
			for(i=0; i<elementCount; i++) {
				
				phi = Math.acos(-1+(2*(i+1)-1)/elementCount);
				theta = Math.sqrt(elementCount*Math.PI)*phi;
				
				mcList[i].cx = radius * Math.cos(theta)*Math.sin(phi);
				mcList[i].cy = radius * Math.sin(theta)*Math.sin(phi);
				mcList[i].cz = radius * Math.cos(phi);
				
				mcList[i].alpha = 0;
				addChild(mcList[i]);
				
				TweenLite.to(mcList[i], 2, {alpha:1});
			}
			
			sineCosine(0,0,0);
			lasta = 1;
			lastb = 1;		
		}

		
		public function update(data:Array):void {
			
			// remove old items		
			for(var i:int=0; i<elementCount; i++)
				(StreamMC(mcList[i])).remove();
			
			// add new items
			var sleepTimer:Timer = new Timer(1000, 1);			
			sleepTimer.addEventListener(TimerEvent.TIMER_COMPLETE, function():void {
				createStreams(data);		
			});
			sleepTimer.start();
		}
		
		public function streamSelected(stream:Stream):void {					
			
			(SphereClient(_root)).streamSelected(stream);
		}
				
		// override rotation functions
		override public function get rotationX():Number { return this.bodyBoll.rotationX; }
		override public function set rotationX(value:Number):void { this.bodyBoll.rotationX = value; }
		
		override public function get rotationY():Number { return this.bodyBoll.rotationY; }
		override public function set rotationY(value:Number):void { this.bodyBoll.rotationY = value; }
		
		override public function get rotationZ():Number { return this.bodyBoll.rotationZ; }
		override public function set rotationZ(value:Number):void { this.bodyBoll.rotationZ = value; }		
	}
}

